package org.msn.server.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.msn.model.dto.ConnectDTO;
import org.msn.model.dto.SendMsgDTO;
import org.msn.model.rest.RestResult;
import org.msn.mapper.database.Repository;
import org.msn.util.JsonUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

@Slf4j
public abstract class WebSocketRequestHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
    protected final Repository repository;

    protected WebSocketRequestHandler(Repository repository) {
        this.repository = repository;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
        if (!(frame instanceof TextWebSocketFrame)) {
            ctx.channel().writeAndFlush(new TextWebSocketFrame("data error"));
            return;
        }

        String text = ((TextWebSocketFrame) frame).text();
        RestResult result = JsonUtil.GSON.fromJson(text, RestResult.class);

        try {
            Class clazz = getEnitiyClass(result.getMsg());
            getMethodByMethodName(result.getMsg(), clazz).invoke(this, ctx,
                    JsonUtil.formJson((Map<String, Object>) result.getData(), clazz));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
    }

    private Method getMethodByMethodName(String methodName, Class clazz) throws NoSuchMethodException {
        Method method = getClass().getDeclaredMethod(methodName, ChannelHandlerContext.class, clazz);
        method.setAccessible(true);
        return method;
    }

    private Class getEnitiyClass(String className) {
        switch (className) {
            case "connect":
                return ConnectDTO.class;
            case "sendMsg":
                return SendMsgDTO.class;
            default:
                throw new IllegalStateException("Unexpected value: " + className);
        }
    }

    /**
     * 发送消息
     *
     * @param ctx
     * @param data
     */
    protected abstract void sendMsg(ChannelHandlerContext ctx, SendMsgDTO data);

    /**
     * 客户端 连接
     *
     * @param ctx
     * @param data
     */
    protected abstract void connect(ChannelHandlerContext ctx, ConnectDTO data);

    protected abstract void getUserByUserId(ChannelHandlerContext ctx, Long userId);
}
